#ifndef _THREADPOOL_H_
#define _THREADPOOL_H_

#include <iostream>
#include <cstddef>
#include <unordered_map>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <thread>
#include <future>

constexpr uint32_t TASK_MAX_THRESHHOLD = INT32_MAX;     ///< 任务队列中任务上限阈值
constexpr size_t THREAD_SIZE_MAX_THRESHHOLD = 1024;     ///< 线程数量上线阈值
constexpr uint32_t THREAD_MAX_IDLE_TIME = 60;           ///< Cached模式下,新创建的线程允许最大空闲时间,单位:秒

/// @brief 线程池支持的模式
enum class PoolMode
{
    MODE_FIXED,      ///< 固定数量的线程
    MODE_CACHED,     ///< 线程数量可动态增长
};

/// @brief 线程类型
class Thread
{
public:
    /// @brief 线程函数对象类型
    using ThreadFunc = std::function<void(uint32_t)>;

    /**
     * @brief 线程对象构造函数 
     * 
     * @param func 函数对象(被执行的)
     */
    explicit Thread(ThreadFunc func)
        : func_(func)
        , threadId_(generateId++)
    {}

    /// @brief 线程对象析构函数
    ~Thread() = default;

    /// @brief 启动线程
    void start()
    {
        // 创建一个线程 来 执行一个线程函数
        std::thread t(func_, threadId_);   // 线程对象t, 线程函数func_
        t.detach(); // 设置分离线程
    }

    /**
     * @brief 获取线程Id(自定义的线程Id)
     * 
     * @return uint32_t 线程Id
     */
    uint32_t getId() const
    {
        return threadId_;
    }

private:
    ThreadFunc func_;
    inline static uint32_t generateId = 0;
    uint32_t threadId_;     ///< 保存线程id
};

/// @brief 线程池类型
class ThreadPool
{
public:
    /// @brief 线程池对象构造函数
    ThreadPool()
        : initThreadSize_(0)
        , threadSizeMaxThreshHold_(THREAD_SIZE_MAX_THRESHHOLD)
        , curThreadSize_(0)
        , idleThreadSize_(0)
        , taskSize_(0)
        , taskQueueMaxThreshHold_(TASK_MAX_THRESHHOLD)
        , poolMode_(PoolMode::MODE_FIXED)
        , isPoolRunning_(false)
    {}

    /// @brief 线程池对象析构函数
    ~ThreadPool()
    {
        isPoolRunning_ = false;

        // 等待线程池里面所有的线程返回 两种状态：阻塞 & 正在执行任务中
        std::unique_lock<std::mutex> lock(taskQueueMutex_);
        notEmpty_.notify_all();
        exitCond_.wait(lock, [&]()->bool { return threads_.size() == 0; });
    }

    /**
     * @brief 设置线程池工作模式
     * 
     * @param mode PoolMode::MODE_FIXED: 固定数量(default), PoolMode::MODE_CACHED: 线程数量可动态增长
     */
    void setMode(PoolMode mode)
    {
        if (checkRunningState())
            return ;
        poolMode_ = mode;
    }

    /**
     * @brief 设置任务队列最大上限阈值
     * 
     * @param threshhold 最大上限阈值
     */
    void setTaskQueueMaxThreshHold(uint32_t threshhold)
    {
        if (checkRunningState())
            return ;
        taskQueueMaxThreshHold_ = threshhold;
    }

    /**
     * @brief 设置cache模式下，线程池中线程上线阈值
     * 
     * @param threadhhlod 线程最大上线阈值
     */
    void setThreadSizeMaxThreshHold(size_t threadhhlod)
    {
        if (checkRunningState())
            return ;
        if (poolMode_ == PoolMode::MODE_CACHED)
            threadSizeMaxThreshHold_ = threadhhlod;
    }

    /**
    * @brief 异步提交一个任务并返回关联的 future 对象
    * 
    * @tparam Func  可调用对象的类型（函数/函数指针/lambda/std::function 等）
    * @tparam Args  参数包类型，表示传递给 func 的参数类型列表
    * 
    * @param func  要提交的可调用对象（函数/任务）
    * @param args  传递给 func 的参数（完美转发）
    * 
    * @return std::future<decltype(func(args...))> 
    *         返回的 future 对象，可通过 get() 获取异步操作结果
    * 
    * @note 参数使用完美转发 (Perfect Forwarding)：
    *       - 保留参数的左右值特性
    *       - 调用形式等价于直接调用 func(args...)
    * 
    * @code{.cpp}
    * // 示例用法：
    * auto future = submit([](int x, int y) { return x + y; }, 2, 3);
    * int result = future.get(); // 结果为 5
    * @endcode
    */
    template<typename Func, typename... Args>
    auto submit(Func&& func, Args&&... args) -> std::future<decltype(func(args...))>
    {
        // 打包任务，放入任务队列
        using RType = decltype(func(args...));
        auto task = std::make_shared<std::packaged_task<RType()>>(
            std::bind(std::forward<Func>(func), std::forward<Args>(args)...)
        );
        std::future<RType> result = task->get_future();

        // 获取锁
        std::unique_lock<std::mutex> lock(taskQueueMutex_);

        // 用户提交任务，最长不能阻塞超过1s，否则判断提交任务失败，返回
        if (!notFull_.wait_for(lock, std::chrono::seconds(1),
            [&]()->bool { return taskQueue_.size() < (size_t)taskQueueMaxThreshHold_; }))
        {
            // 表示notFull_等待1s，条件依然没有满足
            std::cerr << "task queue is full, submit task failed. taskQueue_.size():" << taskQueue_.size() << ", taskQueueMaxThreshHold_: " << taskQueueMaxThreshHold_ << std::endl;

            auto task = std::make_shared<std::packaged_task<RType()>>(
                []()->RType { return RType(); }
            );
            (*task)();
            return task->get_future();
        }

        // 如果有空余，把任务放入队列中 using Task = std::function<void()>
        taskQueue_.emplace([task]() {
            (*task)();
        });
        taskSize_++;

        // 因为新放了任务，任务队列肯定不空，在notEmpty_通知，分配线程执行任务
        notEmpty_.notify_all();

        // cache模式，任务比较紧急，适合场景:小而快的任务 需要根据任务数量和空闲线程的数量，判断是否需要创建新的线程出来
        if (poolMode_ == PoolMode::MODE_CACHED &&
            taskSize_ > idleThreadSize_ &&
            curThreadSize_ < threadSizeMaxThreshHold_)
        {
            std::cout << ">>> create new thread..." << std::endl;
            // 创建新线程
            auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));  // C++14
            auto threadId = ptr->getId();
            threads_.emplace(threadId, std::move(ptr));
            // 启动线程
            threads_[threadId]->start();
            // 修改线程个数相关的变量
            curThreadSize_++;
            idleThreadSize_++;
        }

        // 返回任务的result对象
        return result;
    }


    /**
     * @brief 指定初始线程数量并开启线程池
     * 
     * @param initThreadSize 默认初始线程数量为CPU核心数
     */
    void start(size_t initThreadSize = std::thread::hardware_concurrency())
    {
        isPoolRunning_ = true;
        // 记录初始线程个数
        initThreadSize_ = initThreadSize;
        curThreadSize_ = initThreadSize;
    
        // 创建线程对象
        for (size_t i = 0; i < initThreadSize; ++i)
        {
            // 创建thread对象的时候，把线程函数给到thread线程对象
            auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));  // C++14
            auto threadId = ptr->getId();
            threads_.emplace(threadId, std::move(ptr));
        }
    
        // 启动所有线程
        for (size_t i = 0; i < initThreadSize; ++i)
        {
            threads_[i]->start();   // 需要去执行一个线程函数
            idleThreadSize_++;      // 记录初始空闲线程数量
        }
    }

    // 不允许拷贝
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;
private:
    /**
     * @brief 线程函数(线程执行的具体函数)
     *
     * @param threadId 线程Id(自己生成的)
     * @note 线程池的所有线程从任务队列里面消费任务
     */
    void threadFunc(uint32_t threadId)
    {
        auto lastTime = std::chrono::high_resolution_clock().now();
        while (true)
        {
            Task task;
            {
                // 获取锁
                std::unique_lock<std::mutex> lock(taskQueueMutex_);

                std::cout << "tid:" << std::this_thread::get_id() << " 尝试获取任务..." << std::endl;

                // 锁 + 双重判断
                while (taskQueue_.size() == 0)  // 没有任务,等待任务...
                {
                    // 线程池要结束，回收线程资源
                    if (!isPoolRunning_)
                    {
                        threads_.erase(threadId);
                        std::cout << "tid: " << std::this_thread::get_id() << " exit!!!" << std::endl;
                        exitCond_.notify_all();
                        return ;    // 线程函数结束，线程结束
                    }

                    // cached模式下，有可能已经创建了很多的线程，但是空闲时间超过60s,应该把多余的线程结束回收掉(超过initThreadSize_数量的线程要进行回收)
                    if (poolMode_ == PoolMode::MODE_CACHED)
                    {
                        // 当前时间 - 上一次线程执行时间 > 60s
                        // 每一秒中返回一次 怎么区分：超时返回？还是有任务待执行返回
                        // 条件变量超时返回
                        if (std::cv_status::timeout == notEmpty_.wait_for(lock, std::chrono::seconds(1)))
                        {
                            auto now = std::chrono::high_resolution_clock().now();
                            auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
                            if (dur.count() >= THREAD_MAX_IDLE_TIME &&
                                curThreadSize_ > initThreadSize_)
                            {
                                // 开始回收当前线程

                                // 把线程对象从线程列表容器中删除
                                // threadid => thread对象 => 删除
                                threads_.erase(threadId);   // 注意:不是传入std::this_thread::get_id()
                                // 记录线程数量的相关变量的值修改
                                curThreadSize_--;
                                idleThreadSize_--;

                                std::cout << "tid: " << std::this_thread::get_id() << " exit!!!" << std::endl;
                                return ;    // 结束线程函数，就是结束当前线程了!
                            }
                        }
                    }
                    else
                    {
                        // 等待notEmpty_条件
                        notEmpty_.wait(lock); 
                    }
                }

                idleThreadSize_--;  // 空闲任务数量减1
                std::cout << "tid:" << std::this_thread::get_id() << " 获取任务成功!!!" << std::endl;

                // 从任务队列中取一个任务出来
                task = taskQueue_.front();
                taskQueue_.pop();
                taskSize_--;

                // 如果依然有剩余任务，继续通知其他线程执行任务
                if (taskQueue_.size() > 0)
                {
                    notEmpty_.notify_all();
                }

                // 取出一个任务，进行通知，通知可以继续提交生产任务
                notFull_.notify_all();
            }   // 释放锁

            // 当前线程负责执行这个任务
            if (task != nullptr)
            {
                task();  // 执行function<void()>
            }
            idleThreadSize_++;
            lastTime = std::chrono::high_resolution_clock().now();  // 更新线程执行完任务的时间
        }
    }

    /**
     * @brief 检查线程池的运行状态
     * 
     * @return true 运行
     * @return false 未运行
     */
    bool checkRunningState() const
    {
        return isPoolRunning_;
    }

private:
    std::unordered_map<uint32_t, std::unique_ptr<Thread>> threads_;     ///< 线程列表
    size_t initThreadSize_;                         ///< 初始化的线程数量
    size_t threadSizeMaxThreshHold_;                ///< 线程数量上线阈值
    std::atomic<size_t> curThreadSize_;             ///< 记录当前线程池里面线程的总数量
    std::atomic<uint32_t> idleThreadSize_;          ///< 记录空闲线程的数量

    using Task = std::function<void()>;
    std::queue<Task> taskQueue_;                    ///< 任务队列
    std::atomic<uint32_t>  taskSize_;               ///< 任务的数量
    uint32_t taskQueueMaxThreshHold_;               ///< 任务队列中任务上限阈值

    std::mutex taskQueueMutex_;                     ///< 保证任务队列的线程安全
    std::condition_variable notFull_;               ///< 表示任务队列不满
    std::condition_variable notEmpty_;              ///< 表示任务队列不空
    std::condition_variable exitCond_;              ///< 等待线程资源全部回收

    PoolMode poolMode_;                             ///< 当前线程池模式
    std::atomic<bool> isPoolRunning_;               ///< 表示当前线程的启动状态
};

#endif // _THREADPOOL_H_
